#include "XmlParser.h"
#include <boost/algorithm/string.hpp>
#include "xml/tinyxml2.h"
#include <vector>
#include <algorithm>
using namespace tinyxml2;

XmlParser::XmlParser()
{
	xmlDoc_ = NULL;
}

XmlParser::~XmlParser()
{
	if (xmlDoc_)
	{
		XMLDocument * pDoc = (XMLDocument*)xmlDoc_;
		delete pDoc;
	}
	xmlDoc_ = NULL;
}

NodeToken XmlParser::getRoot()
{
	if (xmlDoc_!= NULL)
	{
		XMLDocument * pDoc = (XMLDocument*) xmlDoc_;
		return (NodeToken)(pDoc->RootElement());
	}
	return NULL;
}

bool XmlParser::loadFromFile(const std::string& fileName)
{
	XMLDocument * pDoc = new XMLDocument();
	XMLError err = pDoc->LoadFile(fileName.c_str());
	if (err != XML_NO_ERROR)
	{
		printf("[XmlParser::loadFromFile] id = %d, msg=%s\r\n", pDoc->ErrorID(), pDoc->ErrorName());
		return false;
	}

	xmlDoc_ = (void*)pDoc;

	return true;
}


XMLElement* ToSubElement(XMLElement *pRootElem, const std::vector<std::string> & subElems)
{
	XMLElement* pSubElem = NULL;
	pSubElem = pRootElem;
	for (size_t n = 0; n < subElems.size(); ++n)
	{
		if (!subElems[n].empty() && pSubElem != NULL)
		{
			pSubElem = pSubElem->FirstChildElement(subElems[n].c_str());
		}
	}

	return pSubElem;
}

std::string XmlParser::getString(NodeToken token, const std::string& namePath)
{
	std::string strRet;
	if (token == NULL)
	{
		token = getRoot();
	}

	XMLElement* pElem = (XMLElement*)token;
	
	if (pElem != NULL && !namePath.empty())
	{
		std::vector<std::string> vecKeys;
		boost::algorithm::split(vecKeys, namePath, boost::algorithm::is_any_of("."));
		if (vecKeys.empty())
		{
			return "";
		}

		std::string strKeys = vecKeys.back();
		vecKeys.pop_back();

		
		if (!vecKeys.empty())
		{
			pElem = ToSubElement(pElem, vecKeys);
		}

		if (pElem != NULL)
		{
			if (pElem != NULL)
			{
				const char * pszData = NULL;
				XMLElement* pDataElem = pElem->FirstChildElement(strKeys.c_str());
				if (pDataElem != NULL)
				{
					pszData = pDataElem->GetText();
				}
				else
				{
					pszData = pElem->Attribute(strKeys.c_str());					
				}
				
				if (pszData != NULL)
				{
					strRet = pszData;
				}
			}
		}
	}

	return strRet;
}

int XmlParser::getInteger(NodeToken token, const std::string& namePath, int defaultVal /*= 0*/)
{
	std::string data = getString(token, namePath);
	return data.empty() ? defaultVal : atoi(data.c_str());
}

double XmlParser::getFloat(NodeToken token, const std::string& namePath, double defaultVal /*= 0*/)
{
	std::string data = getString(token, namePath);
	return data.empty() ? defaultVal : atof(data.c_str());
}

bool XmlParser::getBoolean(NodeToken token, const std::string& namePath, bool defaultVal /*= 0*/)
{
	std::string data = getString(token, namePath);
	if (data.empty())
	{
		return defaultVal;
	}
#ifdef WIN32
	if (_stricmp("true", data.c_str()) == 0 || data[0] == '1')
#else
	if (strcasecmp("true", data.c_str()) == 0 || data[0] == '1')
#endif
	{
		return true;
	}
	return false;
}

NodeToken XmlParser::GetSubNode(NodeToken pParent, const std::string& namePath)
{
	XMLElement* pElem = (XMLElement*)pParent;
	if (pElem == NULL && namePath.empty())
	{
		return getRoot();
	}

	if (namePath.empty())
	{
		return pElem->FirstChildElement();
	}

	std::vector<std::string> vecKeys;
	boost::algorithm::split(vecKeys, namePath, boost::algorithm::is_any_of("."));
	return ToSubElement(pElem, vecKeys);
}

NodeToken XmlParser::GetNextNode(NodeToken token, const char * pszKeyName /*= NULL*/)
{
	XMLElement* pElem = (XMLElement*)token;
	if (pElem != NULL)
	{
		pElem = pElem->NextSiblingElement(pszKeyName);
		return (NodeToken)pElem;
	}

	return NULL;
}

std::string XmlParser::getKeyName(NodeToken token)
{
	XMLElement* pElem = (XMLElement*)token;
	if (pElem == NULL)
	{
		return "";
	}
	const char *pText = pElem->Value();
	
	return pText ? pText : "";
}
